﻿using System;

using Exif.Aspects;
using Exif.Interfaces;

namespace Exif.Tiff
{
	public class TiffInfo : IInitializeNotification
	{
		#region Частные поля класса

		private long _baseOffset;

		private TiffHeader _header;

		private Ifd0th _ifd0th;

		private Ifd1st _ifd1st;

		private IfdExif _ifdExif;

		private IfdGps _ifdGps;

		#endregion

		#region Констурктор

		#endregion

		#region Свойства класса

		public long BaseOffset
		{
			[Initializable]
			get { return this._baseOffset; }
		}

		public TiffHeader Header
		{
			[Initializable]
			get { return this._header; }
		}

		public Ifd0th Ifd0th
		{
			[Initializable]
			get { return this._ifd0th; }
		}

		public Ifd1st Ifd1st
		{
			[Initializable]
			get { return this._ifd1st; }
		}

		public IfdExif IfdExif
		{
			[Initializable]
			get { return this._ifdExif; }
		}

		public IfdGps IfdGps
		{
			[Initializable]
			get { return this._ifdGps; }
		}

		#endregion

		#region Методы класса

		public void Read(IImageProvider provider)
		{
			this.Read(provider, provider.ImageReader.Position);
		}

		public void Read(IImageProvider provider, long offset)
		{
			this._baseOffset = offset;

			var reader = provider.ImageReader;

			this._header = new TiffHeader(reader, this);
			this._ifd0th = new Ifd0th(this);
			this._ifd1st = new Ifd1st(this);
			this._ifdExif = new IfdExif(this);
			this._ifdGps = new IfdGps(this);

			reader.PushEndian(_header.ByteOrder);

			_ifd0th.Read(reader, _baseOffset + _header.Offset0thIfd);
			var subIfdPointer = _ifd0th.ExifIfdPointer;
			if (subIfdPointer != null)
			{
				_ifdExif.Read(reader, _baseOffset + subIfdPointer.ValueOffset);
			}

			subIfdPointer = _ifd0th.GpsInfoIfdPointer;
			if(subIfdPointer != null)
			{
				_ifdGps.Read(reader, _baseOffset + subIfdPointer.ValueOffset);
			}

			if (_ifd0th.NexfIfdOffset != 0)
			{
				_ifd1st.Read(reader, _baseOffset + _ifd0th.NexfIfdOffset);
			}

			reader.PopEndian();

			IsInitialized = true;
			InvokeInitialized();
		}

		public long AbsOffset(long offset)
		{
			return this._baseOffset + offset;
		}

		#endregion

		#region Частные методы класса

		private void InvokeInitialized()
		{
			var initializedHandler = this.Initialized;
			if (initializedHandler != null)
			{
				initializedHandler(this, EventArgs.Empty);
			}
		}

		#endregion

		#region Implementation of IInitializeNotification

		public event EventHandler Initialized;

		public bool IsInitialized { get; private set; }

		#endregion
	}
}